package com.yzd.learnjava.concurrency;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import com.yzd.learnjava.util.Print;

public class Restaurant {
	Meal meal;
	WaitPerson waitPerson = new WaitPerson(this);
	Chef chef = new Chef(this);
	ExecutorService exc = Executors.newCachedThreadPool();
	public Restaurant() {
		exc.execute(chef);
		exc.execute(waitPerson);
	}
	
	public static void main(String[] args) {
		new Restaurant();
	}
}

class Meal{
	private final int orderNum;
	public Meal(int orderNum) {
		this.orderNum = orderNum;
	}
	
	public String toString() {
		return "Meal " + orderNum;
	}
}

class WaitPerson implements Runnable{
	private Restaurant restaurant;
	public WaitPerson(Restaurant restaurant) {
		this.restaurant = restaurant;
	}
	
	public void run() {
		try {
			while(!Thread.interrupted()) {
				synchronized (this) {
					while(restaurant.meal == null) {
						wait();
					}
				}
				Print.print("WaitPerson got " + restaurant.meal);
				synchronized (restaurant.chef) {
					restaurant.meal = null;
					restaurant.chef.notifyAll();
				}
			}
		} catch (InterruptedException e) {
			Print.print("WaitPerson inerrupted");
		}
	}
	
}

class Chef implements Runnable{
	private Restaurant restaurant;
	private int count = 0;
	public Chef(Restaurant r ) {
		this.restaurant = r;
	}
	
	public void run() {
		try {
			while(!Thread.interrupted()) {
				synchronized (this) {
					while(restaurant.meal != null) {
						wait();
					}
				}
				
				if(++count == 10) {
					Print.print("Out of food, closing");
					restaurant.exc.shutdownNow();
				}
				Print.print("Order up! ");
				synchronized(restaurant.waitPerson) {
					restaurant.meal = new Meal(count);
					restaurant.waitPerson.notifyAll();
				}
				
				TimeUnit.MILLISECONDS.sleep(100);
			}
		} catch (InterruptedException e) {
//			e.printStackTrace();
			Print.print("Chef inerrupted");
		}
		
	}
}
